#ifndef http_connection_h__
#define http_connection_h__

#include "common.h"
#include "request.h"
#include "router.h"

#include <memory>

#include "boost/array.hpp"
#include "boost/enable_shared_from_this.hpp"
#include "boost/bind.hpp"
#include "boost/shared_ptr.hpp"
#include "boost/make_shared.hpp"

using namespace boost::asio::ip;

static const int _4Kb_ = 4 * 1024;
class http_connection :
	public boost::enable_shared_from_this<http_connection>
{
public:
	friend class http_server;
	http_connection(boost::asio::io_service& is, root_router& rout):
	_socket(is),
	_is_reading(false),
	_is_writing(false),
	_is_closing(false),
	_keep_alive(false),
	_router(rout)
	{

	}

	virtual ~http_connection()
	{
		close();
	}
	void start()
	{
		_socket.non_blocking(true);
		do_read();
	}

	static boost::shared_ptr<http_connection> make_http_connection(boost::asio::io_service& is, root_router& rout)
	{
		return boost::make_shared<http_connection>(is, rout);
	}
private:
	void do_read()
	{
		if(!_socket.is_open() || _is_reading)
			return;

		_is_reading = true;
		_socket.async_read_some(
			boost::asio::null_buffers(),
			boost::bind(&http_connection::on_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
	}
	void on_read(boost::system::error_code err, size_t bytes_transferred)
	{
		_is_reading = false;
		if (!err)
		{
			try
			{
				std::size_t len = _socket.read_some(boost::asio::buffer(_buffer), err);
				if (!err)
				{
					bool ret = _request.http_parse(_buffer.data(), len);
					if (!ret)
						_is_closing = true;
					else
						http_handler();
				}
			}
			catch (boost::system::error_code&)
			{
				close();
			}
		}
		if (_is_closing)
			close();
	}
	void close()
	{
		try
		{
			if ( _socket.is_open() )
			{				
				_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
				_socket.close();
			}
		}
		catch(boost::system::system_error e)
		{
			// 107 means : shutdown: Transport endpoint is not connected system:107
			// so we don't need to record this kind of error message
			if ( e.code().value() != 107 )
			{
			}
		}
		_is_reading = false;
		_is_writing = false;
		_is_closing = true;
	}

	void http_handler()
	{
		try
		{
			auto router = _router.rout(_request._url);
			if (!router)
			{
				LOGD("don't find any handler for this url [ %s ]", _request._url);
			}
			else
			{
				(*router)(_request, _response);
			}

			if (!_socket.is_open() || _is_writing)
				return;

			_is_writing = true;
			_socket.async_write_some(
				boost::asio::null_buffers(),
				boost::bind(&http_connection::on_write, shared_from_this(), boost::asio::placeholders::error));
		}
		catch (std::exception& e)
		{
			LOGE(e.what());
		}
	}
	void on_write(boost::system::error_code err)
	{
		std::size_t wlen = _socket.write_some(boost::asio::buffer(_response.to_string()), err);
		if (_keep_alive)
			return do_read();
	}
private:
	tcp::socket _socket;
	boost::array<char, _4Kb_> _buffer;
	bool _is_reading;
	bool _is_writing;
	bool _is_closing;

	bool _keep_alive;
	request _request;
	response _response;
	root_router& _router;

// 	TIME_TRACE("http_connection");
};

#endif // http_connection_h__
